﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Xml.Linq;
using System.ComponentModel;

namespace AutoUpgradeManager
{

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        /// <summary>
        /// 是否已经连接到服务器
        /// </summary>
        private bool isLink = false;
        /// <summary>
        /// 终止线程标志
        /// </summary>
        private bool isAbore = false;

        /// <summary>
        /// 当前文件是否上传成功标志
        /// </summary>
        bool IsUpdated = false;     //是否上传标志
        /// <summary>
        /// Webservice客户端
        /// </summary>
        private AutoUpdateService.AutoUpdateClient Client;

        private ComboDataCollection linkDataCollection = new ComboDataCollection();

        private FileBindingCollection fileCollection = new FileBindingCollection();

        BackgroundWorker backworker = new BackgroundWorker();


        public MainWindow()
        {
            InitializeComponent();

            Cmb_Url.ItemsSource = linkDataCollection;

            Lvw_FileInfo.ItemsSource = fileCollection;
            backworker.WorkerSupportsCancellation = true;
            backworker.WorkerReportsProgress = true;
            backworker.DoWork += new DoWorkEventHandler(backworker_DoWork);
            backworker.ProgressChanged += new ProgressChangedEventHandler(backworker_ProgressChanged);
            backworker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backworker_RunWorkerCompleted);

        }

        /// <summary>
        /// 后台任务（进度显示）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backworker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.Dispatcher.BeginInvoke(new Action(() => this.ProgBar_UpdateOnce.Value = e.ProgressPercentage));
        }

        /// <summary>
        /// 后台任务（任务完成反馈）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backworker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            IsUpdated = !(e.Cancelled || e.Error !=null);
        }

        /// <summary>
        /// 后台任务（上传）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backworker_DoWork(object sender, DoWorkEventArgs e)
        {
            string[] argt = e.Argument as string[];

            if (argt==null || argt.Length!=2)
            {
                e.Cancel = true;
                return;
            }

            AutoUpdateService.FileDataInfo dataInfo = new AutoUpdateService.FileDataInfo();

            dataInfo.BuffLen = 1024 * 10;       //10k

            dataInfo.Offset = 0;
            try
            {
                dataInfo.MD5 = getFileMD5(argt[0]);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "上传出错", MessageBoxButton.OK, MessageBoxImage.Error);
                e.Cancel = true;
                return;
            }
            dataInfo.Name = argt[0].Replace(string.Format(@"{0}\", fileCollection.ParentDirPath), "");

            using (System.IO.FileStream fs = new System.IO.FileStream(argt[0], System.IO.FileMode.Open))
            {
                dataInfo.Length = fs.Length;

                while (dataInfo.Offset != dataInfo.Length)
                {
                    dataInfo.Data = new byte[dataInfo.Length - dataInfo.Offset <= dataInfo.BuffLen ? dataInfo.Length - dataInfo.Offset : dataInfo.BuffLen];

                    fs.Position = dataInfo.Offset;

                    fs.Read(dataInfo.Data, 0, dataInfo.Data.Length);

                    dataInfo = Client.UpdateFile(argt[1], dataInfo, "WinAhriman");

                    if (dataInfo == null)
                    {
                        MessageBox.Show("项目文件上传失败...", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                        e.Cancel = true;
                        return;
                    }

                    e.Result = dataInfo.Offset;

                    (sender as BackgroundWorker).ReportProgress((int)(((double)dataInfo.Offset / (double)((long)dataInfo.Length)) * 100), dataInfo.Offset);

                    if (backworker.CancellationPending)
                    {
                        e.Cancel = true;
                        return;
                    }
                }

            }
        }
        /// <summary>
        /// 服务连接按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void BtnLink_Click(object sender, RoutedEventArgs e)
        {
            isLink = false;

            Cmb_PrjNameList.Items.Clear();

            if (Cmb_Url.Text == "")
            {
                MessageBox.Show("请输入正确的服务地址...", "错误", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            ProgBar_Update.Visibility = System.Windows.Visibility.Visible;
            ProgBar_Update.IsIndeterminate = true;

            new System.Threading.Thread(() =>
            {
                try
                {
                    Client = new AutoUpdateService.AutoUpdateClient();

                    this.Dispatcher.Invoke(new Action(() =>
                    {
                        Client.Endpoint.Address = new System.ServiceModel.EndpointAddress(Cmb_Url.Text);
                        isLink = RefreshCombList();
                        linkDataCollection.Add(Cmb_Url.Text);
                    }));

                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace, "服务错误", MessageBoxButton.OK, MessageBoxImage.Error);
                }

                ProgBar_Update.Dispatcher.BeginInvoke(new Action(() =>
                {
                    ProgBar_Update.Visibility = System.Windows.Visibility.Hidden;
                    ProgBar_Update.IsIndeterminate = false;
                }));
            }).Start();

        }
        /// <summary>
        /// 自动升级服务器项目配置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_SetProject_Click(object sender, RoutedEventArgs e)
        {
            if (!isLink)
            {
                MessageBox.Show("服务尚未连接，无法进行操作...", "配置失败", MessageBoxButton.OK, MessageBoxImage.Information);
                return;
            }

            ControlForm.Window_ServiceSetup window = new ControlForm.Window_ServiceSetup();

            window.Client = Client;

            window.ShowDialog();
        }
        /// <summary>
        /// 刷新项目列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_Refresh_Click(object sender, RoutedEventArgs e)
        {
            if (!isLink) return;

            RefreshCombList();
        }

        /// <summary>
        /// 清空服务器项目文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_ClearProject_Click(object sender, RoutedEventArgs e)
        {
            if (Cmb_PrjNameList.Text == "")
            {
                MessageBox.Show("请选择一个项目...", "提示", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            if (MessageBox.Show(string.Format("是否确认清除服务器项目【{0}】的所有文件...", Cmb_PrjNameList.Text), "询问", MessageBoxButton.OKCancel, MessageBoxImage.Question) == MessageBoxResult.Cancel) return;

            if (!Client.ProjectFolderClear(Cmb_PrjNameList.Text))
            {
                MessageBox.Show("项目文件清理失败...", "提示", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            else
            {
                MessageBox.Show("项目文件清理完成...", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
            }

        }

        /// <summary>
        /// 刷新项目列表
        /// </summary>
        private bool RefreshCombList()
        {
            try
            {
                Cmb_PrjNameList.ItemsSource = Client.GetPrjNames();
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace, "服务错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }

        /// <summary>
        /// CmboBox文本框键盘回车处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Cmb_Url_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter && Cmb_Url.Text != "")
            {
                BtnLink_Click(BtnLink, new RoutedEventArgs());

            }

            e.Handled = true;
        }

        /// <summary>
        /// 链接对象删除
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Cmb_Url_ListItemDel_Event(object sender, MouseButtonEventArgs e)
        {
            System.Reflection.PropertyInfo pi = typeof(ComboBox).GetProperty("HighlightedItem", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            object o = pi.GetValue(Cmb_Url, new object[] { });

            XElement x = o as XElement;

            linkDataCollection.Remove(x);

            Cmb_Url.IsDropDownOpen = false;

            e.Handled = true;

        }

        /// <summary>
        /// 打开文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_OpenFile_Click(object sender, RoutedEventArgs e)
        {
            if (Cmb_PrjNameList.Text == "")
            {
                MessageBox.Show("请选择一个项目，再通过打开文件选择项目文件...", "提示", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }

            ControlForm.Window_FolderBrowser folderBrower = new ControlForm.Window_FolderBrowser();

            if (!(bool)folderBrower.ShowDialog()) return;

            fileCollection.RetrievalFolderPath(folderBrower.SelectedPath);

        }
        /// <summary>
        /// 文件列表清除
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_ClearList_Click(object sender, RoutedEventArgs e)
        {
            if (!isLink) return;
            fileCollection.Clear();
        }

        /// <summary>
        /// 开始上传文件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_StarUpdate_Click(object sender, RoutedEventArgs e)
        {
            if (!isLink || Cmb_PrjNameList.Text == "" || Lvw_FileInfo.Items.Count == 0) return;

            isAbore = false;

            #region------------------设置窗体模糊特效-----------------------------

            System.Windows.Media.Effects.BlurEffect be = new System.Windows.Media.Effects.BlurEffect();

            be.Radius = 5;
            be.KernelType = System.Windows.Media.Effects.KernelType.Gaussian;

            this.Effect = be;

            #endregion

            ControlForm.Window_PrjVersionSetup windowVersion = new ControlForm.Window_PrjVersionSetup();

            windowVersion.SetStartProgramList(from s in fileCollection
                                              where s.Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)
                                              select string.Format(@"{0}\{1}", s.Path, s.Name).Replace(fileCollection.ParentDirPath + '\\', ""));

            if (!(bool)windowVersion.ShowDialog())
            {
                windowVersion = null;
                this.Effect = null;
                return;
            }

            string prjversion = windowVersion.PrjVersion;
            string prjdatetime = windowVersion.PrjDataTime;
            string prjname = Cmb_PrjNameList.Text;
            string prjStartProgram = windowVersion.StartProgram;

            windowVersion = null;
            this.Effect = null;

            if (MessageBox.Show(string.Format("是否确认上传？\r\n项目名称：{0}\r\n项目版本：{1}\r\n更新时间：{2}", prjname,
                                                                                                                    prjversion,
                                                                                                                    prjdatetime), "上传确认",
                                                                                                                    MessageBoxButton.OKCancel,
                                                                                                                    MessageBoxImage.Question) == MessageBoxResult.Cancel) return;

            ProgBar_Update.Minimum = 0;
            ProgBar_Update.Maximum = fileCollection.Count();
            ProgBar_Update.Value = 0;

            ProgBar_Update.Visibility = System.Windows.Visibility.Visible;
            ProgBar_UpdateOnce.Visibility = System.Windows.Visibility.Visible;
            Btn_StarUpdate.IsEnabled = false;

            System.Threading.Tasks.Task.Factory.StartNew(() =>           //开个一个新线程，避免过程阻塞主线程
            {
                for (int i = 0; i < fileCollection.Count(); i++)                //文件信息集合遍历上传
                {
                    if (isAbore) break;

                    FileBindingInfo file = fileCollection[i];

                    string filePath = string.Format(@"{0}\{1}", file.Path, file.Name);

                    this.Dispatcher.BeginInvoke(new Action(() => 
                    {
                        Lvw_FileInfo.ScrollIntoView(file);
                        this.ProgBar_Update.Value = i + 1;
                    }));

                    if (filePath == string.Format(@"{0}\{1}", fileCollection.ParentDirPath, prjStartProgram))
                    {
                        using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Append))
                        {
                            fs.Position = fs.Length;

                            fs.Write(new byte[] { (byte)'<', (byte)'s', (byte)'t', (byte)'a', (byte)'r', (byte)'t', (byte)'>' }, 0, 7);
                        }
                    }

                    backworker.RunWorkerAsync(new string[]{filePath,prjname});  //开启后台任务

                    while (backworker.IsBusy)
                    {
                        System.Threading.Thread.Sleep(10);
                    }

                    if (filePath == string.Format(@"{0}\{1}", fileCollection.ParentDirPath, prjStartProgram))
                    {
                        using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite))
                        {
                            fs.SetLength(fs.Length - 7);
                        }


                    }

                    file.State = IsUpdated ? "已上传" : "上传失败";

                    if (!IsUpdated) break;
                }

                if (IsUpdated  && !isAbore)          //如果全部上传成功，才更新版本
                {
                    IsUpdated = Client.SetProjectVersion(prjversion, prjdatetime, prjname, "WinAhriman");
                }
                ProgBar_Update.Dispatcher.BeginInvoke(new Action(() =>
                {
                    ProgBar_Update.Visibility = System.Windows.Visibility.Hidden;
                    ProgBar_UpdateOnce.Visibility = System.Windows.Visibility.Hidden;
                    Btn_StarUpdate.IsEnabled = true;
                }));
                if (isAbore)
                {
                    MessageBox.Show(string.Format("项目:【{0}】文件上传被终止...", prjname), "提示", MessageBoxButton.OK, MessageBoxImage.Information);
                }
                else
                {
                    MessageBox.Show(string.Format("项目:【{0}】文件上传{1}...", prjname, IsUpdated ? "成功" : "失败"), "提示", MessageBoxButton.OK, IsUpdated ? MessageBoxImage.Information : MessageBoxImage.Exclamation);
                }
            });
        }

        /// <summary>
        /// 终止上传操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btn_Abore_Click(object sender, RoutedEventArgs e)
        {
            if (!isLink) return;
            if (backworker.IsBusy) backworker.CancelAsync();
            isAbore = true;
        }

        /// <summary>
        /// 文件夹拖放
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Lvw_FileInfo_DragOver(object sender, DragEventArgs e)
        {
            IDataObject data = e.Data;

            if (!isLink
                || Cmb_PrjNameList.Text == ""
                || !data.GetDataPresent(DataFormats.FileDrop)
                || ((System.Array)e.Data.GetData(DataFormats.FileDrop)).Length != 1)
            {
                e.Effects = DragDropEffects.None;
                e.Handled = true;
                return;
            }
            else
            {
                object o = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0);

                if (!System.IO.Directory.Exists(o.ToString()))
                {
                    e.Effects = DragDropEffects.None;
                    e.Handled = true;
                    return;
                }
                e.Effects = DragDropEffects.Move;
            }

        }
        /// <summary>
        /// 文件夹拖放（放下）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Lvw_FileInfo_Drop(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return;

            object o = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0);

            if (!System.IO.Directory.Exists(o.ToString())) return;

            fileCollection.Clear();

            new System.Threading.Thread(() =>
                {
                    this.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        fileCollection.RetrievalFolderPath(o.ToString());
                    }));
                }).Start();
        }

        /// <summary>
        /// 获取文件MD5效验码
        /// </summary>
        /// <param name="filepath"></param>
        /// <returns></returns>
        private string getFileMD5(string filepath)
        {
            System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();

            string md5CheckCode = "";

            using (System.IO.FileStream fs = new System.IO.FileStream(filepath, System.IO.FileMode.Open))
            {
                md5CheckCode = BitConverter.ToString(md5.ComputeHash(fs)).Replace("-", "");
            }
            return md5CheckCode;
        }

    }

    /// <summary>
    ///  ComboBox列表集合(带自动更新)
    /// </summary>
    internal class ComboDataCollection : ObservableCollection<XElement>
    {
        const string CONST_LINKPATH = "ServiceUrl.xml";

        XDocument xdoc = null;

        public ComboDataCollection()
            : base()
        {
            xdoc = new XDocument();
            xdoc.Changed += new EventHandler<XObjectChangeEventArgs>(xdoc_Changed);
            try
            {
                xdoc = XDocument.Load(CONST_LINKPATH);
            }
            catch
            {
                xdoc.Add(new XElement("Links"));
            }

            IEnumerable<XElement> elementItems = from xe in xdoc.Descendants("Link")
                                                 select xe;
            foreach (XElement x in elementItems)
            {
                this.Add(x);
            }
        }

        public void Add(string url)
        {
            IEnumerable<XElement> items = from x in xdoc.Descendants("Link")
                                          where x.Attribute("Url").Value == url
                                          select x;
            if (items.Count() == 0)
            {

                XElement x = new XElement("Link", new XAttribute("Url", url));

                xdoc.Element("Links").Add(x);

                xdoc.Save(CONST_LINKPATH);

                this.InsertItem(this.Count, x);
            }
        }

        protected override void RemoveItem(int index)
        {
            var links = from x in xdoc.Descendants("Link")
                        where x.Attribute("Url").Value == this[index].Attribute("Url").Value
                        select x;

            if (links.Count() > 0)
            {
                links.First().Remove();

                xdoc.Save(CONST_LINKPATH);
            }
            base.RemoveItem(index);
        }


        private void xdoc_Changed(object sender, XObjectChangeEventArgs e)
        {
            xdoc.Save(CONST_LINKPATH);
        }
    }
}
